/*
    Copyright (C) 2009 Giacomo Spigler

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#include <cutil.h>
#include <cuda_runtime.h>


#include <cv.h>
#include <highgui.h>


#include "../cuda/standard.h"
#include "../cuda/gabor.h"



int main() {
  IplImage *im=cvLoadImage("l.png");


  #ifdef DEBUG
    unsigned int hTimer;
    cutCreateTimer(&hTimer);
    cutStartTimer(hTimer);
  #endif


  int w_host[NUMSCALES], h_host[NUMSCALES];

  IplImage *pyr[NUMSCALES];
  pyr[0]=cvCreateImage(cvSize(im->width, im->height), 8, 1);
  w_host[0]=im->width; h_host[0]=im->height;
  for(int i=1; i<NUMSCALES; i++) {
    pyr[i]=cvCreateImage(cvSize(pyr[i-1]->width/INVERSESCALERATIO, pyr[i-1]->height/INVERSESCALERATIO), 8, 1);

    w_host[i]=pyr[i]->width; h_host[i]=pyr[i]->height;
  }

  int *w_dev, *h_dev;
  InitWidthsHeights(w_host, h_host, &w_dev, &h_dev);

  unsigned char *pyr_dev;
  unsigned char *s1_dev[4];
  unsigned char *c1_dev[4];
  size_t pyr_dev_pitch;
  size_t c1_pitch;

  int nums2, n4, n8;
  unsigned char *patch4x4; //device
  unsigned char *patch8x8; //device

  unsigned char *s2_dev; //device
  size_t s2_pitch;
  LoadS2Patches("s2.patch", &nums2, &n4, &n8, &patch4x4, &patch8x8);

  unsigned char *c2_dev;
  unsigned char *c2_host;

  InitPyramidBuffer(pyr, &pyr_dev, s1_dev, c1_dev, &pyr_dev_pitch, &c1_pitch, &s2_dev, nums2, &s2_pitch, &c2_dev, &c2_host);

  #ifdef DEBUG
    cutStopTimer(hTimer);
    printf("Initialization time: %fms\n", cutGetTimerValue(hTimer));
  #endif



  #ifdef DEBUG
    cutCreateTimer(&hTimer);
    cutStartTimer(hTimer);
  #endif

  SetPyramid_0(im, pyr, pyr_dev, pyr_dev_pitch);

  #ifdef DEBUG
    cutStopTimer(hTimer);
    printf("Pyramid Setup time: %fms\n", cutGetTimerValue(hTimer));
  #endif



  #ifdef DEBUG
    cutCreateTimer(&hTimer);
    cutStartTimer(hTimer);
  #endif

  ComputeS1_1(pyr_dev, s1_dev, w_host, h_host, w_dev, h_dev, pyr_dev_pitch,   pyr);

  #ifdef DEBUG
    cutStopTimer(hTimer);
    printf("S1 Computing time: %fms\n", cutGetTimerValue(hTimer));
  #endif



  #ifdef DEBUG
    cutCreateTimer(&hTimer);
    cutStartTimer(hTimer);
  #endif

  ComputeC1_2(s1_dev, c1_dev, w_host, h_host, w_dev, h_dev, pyr_dev_pitch, c1_pitch,   pyr);

  #ifdef DEBUG
    cutStopTimer(hTimer);
    printf("C1 Computing time: %fms\n", cutGetTimerValue(hTimer));
  #endif



  #ifdef DEBUG
    cutCreateTimer(&hTimer);
    cutStartTimer(hTimer);
  #endif

  ComputeS2_3(c1_dev, w_host, h_host, w_dev, h_dev, c1_pitch, s2_pitch, s2_dev, nums2, n4, n8, patch4x4, patch8x8,   pyr);

  #ifdef DEBUG
    cutStopTimer(hTimer);
    printf("S2 Computing time: %fms\n", cutGetTimerValue(hTimer));
  #endif



  #ifdef DEBUG
    cutCreateTimer(&hTimer);
    cutStartTimer(hTimer);
  #endif

  ComputeC2_4(w_host, h_host, w_dev, h_dev, s2_pitch, s2_dev, nums2, c2_dev, c2_host,   pyr);

  #ifdef DEBUG
    cutStopTimer(hTimer);
    printf("C2 Computing time: %fms\n", cutGetTimerValue(hTimer));
  #endif






  for(int i=0; i<10; i++) {
    printf("%d\n", c2_host[i]);
  }





  printf("Last CUDA error: %s\n", cudaGetErrorString(cudaGetLastError()));


  cvNamedWindow("l", CV_WINDOW_AUTOSIZE);
  cvShowImage("l", pyr[0]);
  cvWaitKey(0);

  cvDestroyWindow("l");

  cvReleaseImage(&im);


  FreeAll(w_dev, h_dev, pyr_dev, s1_dev, c1_dev, patch4x4, patch8x8, s2_dev, c2_dev, c2_host);

  return 0;
}




